test(conformance): plugin hook-info field-shape handlers (10-19..10-23) - #602
test(conformance): plugin hook-info field-shape handlers (10-19..10-23)#602wangyb-A wants to merge 5 commits into
Conversation
fd7c2c6 to
0bd1029
Compare
Plugin hook infos dropped state that the Python and JS SDKs carry, so a Java plugin could not see per-operation replay status at the attempt and change hooks, nor operation state at the invocation hooks. Attempt and change-item fields: - UserFunctionStartInfo / UserFunctionEndInfo gain `isReplay`, the operation-level indicator for whether THIS operation was observed via checkpointed state. This is distinct from the existing `isReplayingChildren`, which describes the child operations of a context body and does not substitute for it. - OperationChangeItemInfo was a reduced record; it now carries the full operation surface (`status`, `attempt`, `isReplay`, `error`), ordered to match OperationEndInfo, so an operation seen through a change delta exposes the same fields as through the per-operation hooks. Invocation-info enrichment: - InvocationInfo gains `operations` and `updatedOperations`. - InvocationEndInfo gains `operations` and `executionStartTime`; the latter was present on the start info but dropped from the end record, forcing plugins to correlate back to the start hook. - `updatedOperations` derives from the input's UpdatedOperationIds intersected with the tracked operations, so it is empty on the first invocation and names the externally-completed operations on a replay. - The end-info snapshot is taken at end time, so unlike the start info it also includes operations created during the invocation. ExecutionManager now snapshots the operation ids delivered in the initial state and exposes non-mutating accessors for them. The attempt hook needs the replay indicator at its firing site, but getOperation() delegates to getOperationAndUpdateReplayState, which flips REPLAY to EXECUTION mode as a side effect; reading it from a plugin-hook site would mutate execution state. wasObservedAtInvocationStart is a pure containment check instead, and gives one consistent definition of `isReplay` across the attempt, change and invocation hooks. Both invocation maps are keyed by operation id and valued with OperationChangeItemInfo, now the richest operation snapshot record the SDK has, so a single conversion path feeds the change hook and both invocation hooks. The record name is a wart in this role; renaming it is left as a follow-up. These are positional records, so the added components surface every constructor call site. No defaulting overloads were introduced: a convenience constructor is exactly how a future internal call site would silently ship empty maps to plugins, which is the failure mode this change fixes. Call sites in the OpenTelemetry plugin tests were updated mechanically. Payload surfaces stay out of scope: no `result` and no execution input/result on any info. Verified with the full module build, unit tests and spotless:check. The conformance handlers that assert these field shapes, and the live suite results, are in the stacked follow-up PR. Refs: #604
The parity fix beneath this commit exposes fields the shape handlers could not previously read. Dump them so 10-19, 10-21 and 10-22 assert the real surface rather than recording its absence: - 10-19: operationsCount and updatedOperationsCount on invocation-start, operationsCount and executionStartTimestamp on invocation-end. - 10-21: isReplay on attempt-start and attempt-end, alongside the distinct isReplayingChildren (dumped unasserted). - 10-22: attempt and isReplay on each change delta item. The handler javadocs previously documented these as missing Java surfaces; that prose is updated to describe what is now exposed and to note that payload fields remain deliberately absent.
3907209 to
4f5639c
Compare
0bd1029 to
2b28744
Compare
| .str("parentId", info.parentId()) | ||
| .num("attempt", info.attempt()) | ||
| .time("startTimestamp", info.startTimestamp()) | ||
| .bool("isReplayingChildren", info.isReplayingChildren()) |
There was a problem hiding this comment.
Codex AI review
[P2] Include the operation-level replay flag. UserFunctionStartInfo exposes isReplay() separately from isReplayingChildren(), and this scenario produces both replayed and live context starts. Omitting it prevents 10-23 from detecting an incorrect context-operation replay flag. Emit both fields.
| .bool("isReplayingChildren", info.isReplayingChildren()) | |
| .bool("isReplay", info.isReplay()) | |
| .bool("isReplayingChildren", info.isReplayingChildren()) |
Codex AI reviewFound one gap in the context hook field-shape coverage. Review was read-only; tests were not run. Reviewed commit |
| raw("hook", "\"" + hook + "\""); | ||
| } |
There was a problem hiding this comment.
Claude AI review
Maintainability (low): The Rec single-line JSON builder — the constructor plus str/num/bool/time/raw/emit and the static upper/msg/quote methods (~90 lines) — is duplicated verbatim in all five new handlers (PluginAttemptInfoShape, PluginContextInfoShape, PluginInvocationInfoShape, PluginOperationChangeShape, PluginOperationInfoShape), roughly 360 duplicated lines out of the PR's 982 additions.
PluginSupport already exists as the documented home for shared plugin-conformance helpers (it hosts arnField, isStep, isContext, etc.). Because every handler emits the same escaped JSON shape, any future fix to the JSON escaping or field formatting must be applied in five places, and the copies can silently diverge.
Fix: Hoist Rec (and upper/msg/quote) into PluginSupport (or a new package-private PluginJsonRecord class) and have each handler construct the shared type, deleting the per-file copies.
Claude AI reviewVerified all five new conformance handlers plus the
One low-severity maintainability finding: the Residual test risk: these handlers have no local/unit coverage — per AGENTS.md, conformance tests are validated only by the live cloud suite in a separate repo, and the PR notes the emitted records were not retained as an artifact (the stack, and its CloudWatch log groups, are deleted after the run). Correctness of the field-shape assertions therefore rests entirely on that live run rather than anything reproducible in this repo. Reviewed commit |
4f5639c to
b42d0db
Compare
Summary
Adds 5 conformance handlers (
conformance-tests/src/main/java/plugin/Plugin{InvocationInfo,OperationInfo,AttemptInfo,OperationChange,ContextInfo}Shape.java) plustemplate_plugin.yamlentries implementing plugin hook-info FIELD-SHAPE requirements 10-19..10-23 from aws/aws-durable-execution-conformance-tests#72 (land that PR first).Each handler logs ONE single-line JSON record per hook event: a canonical camelCase dump of that hook's own info record, with null/unexposed fields OMITTED so a missing key fails its assertion. Real SDK APIs only, spotless-clean.
Stacked PR
Top of a 2-PR stack — base is the parity-fix branch, not
main.plugin-hook-parity-fix), exposes the missing hook-info fields.The dependency is real, not cosmetic: the final commit here dumps
operations/updatedOperations,isReplay,attempt,executionInput,executionResultand the operationresult, which only exist after the parity fix. Review the base PR first; merge it first.Testing
Live plugin conformance suite (us-west-2), run against the full stack: 23 cases, 0 failures, 2 skipped — 21/21 covered, up from 18/21.
The three prior failures were the deliberate parity signals these handlers exist to produce; the base PR resolves all three.
OperationInfo.status, subType tokens, and correctisReplayingChildrensemantics), plus the entire mapped 10-1..10-17 regression.One caveat on evidence: the runner asserts the
ExpectedLogsfield-presence probes against CloudWatch during the run and then deletes the stack, which takes the log groups with it. The passing assertions are the record; the raw emitted hook records were not retained as an artifact.Closes #604